package com.alone.embedded.lucene.core;

import com.alone.embedded.lucene.exception.EmbeddedLuceneException;
import com.alone.embedded.lucene.repository.RepositoryInterceptor;
import com.alone.embedded.lucene.repository.hightlight.HighlightRender;
import com.alone.embedded.lucene.transaction.ElTransactionManager;
import lombok.Getter;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.search.IndexSearcher;

import java.io.IOException;
import java.nio.file.Path;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 核心资源上下文
 *
 * @author Alone
 * @date 2022/8/4 9:28 上午
 */
public class Source<T> {

    private final Path indexPath;

    @Getter
    private final Analyzer analyzer;

    private final SourceFactory factory;

    @Getter
    private final DocFactory<T> docFactory;

    @Getter
    private final Class<T> docClass;

    @Getter
    private final RepositoryInterceptor repositoryInterceptor;

    @Getter
    private final ElTransactionManager txManager;

    @Getter
    private volatile IndexWriter writer;
    @Getter
    private volatile IndexSearcher searcher;
    private final Lock updateLock = new ReentrantLock();

    Source(Class<T> docClass,
           Path indexPath,
           Analyzer analyzer,
           SourceFactory factory,
           DocFactory<T> docFactory,
           RepositoryInterceptor repositoryInterceptor,
           ElTransactionManager txManager
    ) {
        this.docClass = docClass;
        this.indexPath = indexPath;
        this.analyzer = analyzer;

        this.factory = factory;
        IndexWriter writer = factory.createWriter(indexPath, analyzer);
        IndexSearcher searcher = factory.createSearcher(writer);
        this.writer = writer;
        this.searcher = searcher;

        this.docFactory = docFactory;
        this.repositoryInterceptor = repositoryInterceptor;
        this.txManager = txManager;
    }

    public void commit() {
        updateLock.lock();
        try {
            if (writer.hasUncommittedChanges()) {
                writer.flush();
                writer.commit();
                searcher = factory.createSearcher(writer);
            }
        } catch (IOException e) {
            throw EmbeddedLuceneException.of(e);
        } finally {
            updateLock.unlock();
        }
    }

    public void rollback() {
        updateLock.lock();
        try {
            if (writer.hasUncommittedChanges()) {
                writer.rollback();
                writer = factory.createWriter(indexPath, analyzer);
                searcher = factory.createSearcher(writer);
            }
        } catch (IOException e) {
            throw EmbeddedLuceneException.of(e);
        } finally {
            updateLock.unlock();
        }
    }

    public T getJavaBean(int doc, HighlightRender highlightRender, Set<String> selectFieldSet) throws IOException {
        if (null == selectFieldSet || selectFieldSet.isEmpty()) {
            return docFactory.toJavaBean(searcher.doc(doc), highlightRender);
        } else {
            return docFactory.toJavaBean(searcher.doc(doc, selectFieldSet), highlightRender);
        }
    }

    public ElDocument<T> getElDocument(int doc, HighlightRender highlightRender, Set<String> selectFieldSet) {
        return docFactory.getElDocument(doc, this, highlightRender, selectFieldSet);
    }

}
